using System;
using System.Text;
using System.Collections.Specialized;
using System.Xml;

namespace stunnware.CRM.Fetch
{
    /// <summary>
    /// The FetchColumnSet class is used to specify the attributes in a query.
    /// </summary>
    public class FetchColumnSet
    {

        private bool _allColumns;
        private StringCollection _columns;
        private FetchAggregate _aggregate;
        private string _alias;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public FetchColumnSet()
        {
        }

        /// <summary>
        /// Creates a new column set with the specified attributes.
        /// </summary>
        /// <param name="columns">The attributes to return.</param>
        public FetchColumnSet(string[] columns)
        {
            _columns = new StringCollection();
            _columns.AddRange(columns);
        }

        /// <summary>
        /// Creates a new column set.
        /// </summary>
        /// <param name="allColumns">If true, the column set specifies that all attributes should be returned.</param>
        public FetchColumnSet(bool allColumns)
        {
            _allColumns = allColumns;
        }

        /// <summary>
        /// Currently only Count is supported. If you specify Count, the column set should only contain a single attribute.
        /// </summary>
        public FetchAggregate Aggregate
        {
            get
            {
                return _aggregate;
            }

            set
            {
                _aggregate = value;
            }
        }

        /// <summary>
        /// If true, all attributes are to be returned. Otherwise the <see cref="Columns"/> collection is used.
        /// </summary>
        public bool AllColumns
        {
            get
            {
                return _allColumns;
            }

            set
            {
                _allColumns = value;
            }
        }

        /// <summary>
        /// Specifies the attributes to return. This property is ignored if <see cref="AllColumns"/> is set to true.
        /// </summary>
        public StringCollection Columns
        {
            get
            {
                return _columns;
            }

            set
            {
                _columns = value;
            }
        }

        /// <summary>
        /// Defines the alias if an aggregate is specified. You must set this property when using an aggregate.
        /// </summary>
        public string Alias
        {
            get
            {
                return _alias;
            }

            set
            {
                _alias = value;
            }
        }

        /// <summary>
        /// Checks if an attribute exists in the <see cref="Columns"/> collection.
        /// </summary>
        /// <param name="attribute">The attribute name,</param>
        /// <returns></returns>
        public bool Contains(string attribute)
        {
            return (Columns != null) ? Columns.Contains(attribute) : false;
        }

        /// <summary>
        /// Adds the definition of this class to an XML document.
        /// </summary>
        /// <param name="entityNode"></param>
        internal void AddToFetchDocument(XmlElement entityNode)
        {

            if (AllColumns)
            {
                XmlElement allColumns = entityNode.OwnerDocument.CreateElement("all-attributes");
                entityNode.AppendChild(allColumns);
            }

            else
            {
                if (Columns != null)
                {
                    foreach (string column in Columns)
                    {
                        XmlElement columnNode = FetchXmlDocument.AddElement(entityNode, "attribute");
                        FetchXmlDocument.AddAttribute(columnNode, "name", column);

                        if (Aggregate != FetchAggregate.None)
                        {
                            string node;
                            //string alias;
                            switch (Aggregate)
                            {
                                case FetchAggregate.Count:
                                    { node = "count"; break; }
                                //case FetchAggregate.Sum:
                                //    { node = "sum"; break; }
                                //case FetchAggregate.Average:
                                //    { node = "average"; break; }
                                default: throw new ArgumentException("Unknown aggregate");

                            }
                            FetchXmlDocument.AddAttribute(columnNode, "aggregate", node);

                            if ((Alias != null) && (Alias.Length > 0))
                            {
                                FetchXmlDocument.AddAttribute(columnNode, "alias", Alias);
                            }

                            return;
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// The possible aggregates.
    /// </summary>
    public enum FetchAggregate
    {
        /// <summary>
        /// No aggregate (default)
        /// </summary>
        None,

        /// <summary>
        /// The Count aggregate
        /// </summary>
        Count,

        ///// <summary>
        ///// Average aggregate
        ///// </summary>
        //Average,

        ///// <summary>
        ///// Sum aggregate
        ///// </summary>
        //Sum
    }
}